<?php

namespace app\service;

use app\controller\frontend\ListController;
use app\exception\ModelEmptyException;
use app\model\Category;
use app\model\CategorySubContent;
use app\model\SubContent;
use app\model\Theme;
use app\model\Website;
use think\facade\Cache;
use think\facade\Log;
use think\facade\View;

/**
 * 网站静态化服务
 */
class StaticFileService
{
    public static $forbidNames = [
        '/xml',
        '/view',
        '/tinymce',
        '/themes',
        '/system_file',
        '/storage',
        '/static',
        '/sitemap_html',
        '/poster_preview',
        '/design',
        '/backend'
    ];

    private $viewBase;
    private $realSiteId;
    private $lang;
    private $theme;

    private function init($admin, $siteId, $lang)
    {
        $this->viewBase = config('view.view_dir_name');
        $this->realSiteId = $siteId;
        $this->lang = $lang;

        $where = [
            'seller_id' => $admin['seller_id'],
            'website_id' => $siteId,
            'lang' => $lang,
            'is_active' => 1
        ];
        $Theme = new Theme();
        $theme = $Theme->getActiveTheme($where)['data']->toArray();
        $themeName = $theme['theme'];
        $this->theme = $themeName;

        define('INDEX_SITE_ID', $this->realSiteId);
        define('INDEX_REAL_SITE_ID', $this->realSiteId);
        define('INDEX_SELLER_ID', $admin['seller_id']);
        define('INDEX_LANG', $this->lang);
    }

    public function updateCategoryCache($param)
    {
        $where = [
            ['seller_id', '=', $param['admin']['seller_id']],
            ['website_id', '=', $param['site_id']],
            ['type', '<>', 3],
        ];
        if (empty($param['lang'])) {
            $param['lang'] = 'zh';
        }
        $where[] = ['lang', '=', $param['lang']];

        $Website = new Website();
        $website = $Website->getWebsite(['id' => $param['site_id'], 'seller_id' => $param['admin']['seller_id']])['data'];
        $domain = $website['domain'];
        $cateCacheKey = 'hc_cate_html' . $param['admin']['seller_id'] . '_' . $param['site_id'] . '_' . $param['lang'];

        $categoryList = $this->getCategoryList($where, $param, $domain, $website);
        $categoryTreeList = makeTree($categoryList);
        Cache::set($cateCacheKey, $categoryTreeList);
        return dataReturn(0,  lang('操作成功'), ['tree' => $categoryTreeList, 'list' => $categoryList]);
    }

    protected function getCategoryList($where, $param, $domain, $website)
    {
        $categoryModel = new Category();
        $categoryList = $categoryModel->where($where)->select()->each(function (&$item) use ($param, $domain, $website) {
            $lang = '/' . $param['lang'] . '/';
            if ($param['lang'] == 'zh') {
                $lang = '/';
            }
            if ($website['id'] != 1) {
                $lang = '/' . $domain . $lang;
            }
            // 获取路径
            if (!empty($item['alias'])) {
                if ($item['alias'] == '/') {
                    $item['path'] = $lang . 'index.' . config('route.url_html_suffix');
                    $item['detailPath'] = $lang . 'index/';
                } else {
                    $item['path'] = $lang . $item['alias'] . '.' . config('route.url_html_suffix');
                    $item['detailPath'] = $lang . $item['alias'] . '/';
                }
            } else {
                $item['path'] = $lang . 'list/index/' . $item['id'] . '.' . config('route.url_html_suffix');
                $item['detailPath'] = $lang . 'list/index/' . $item['id'] . '/';
            }
        });
        return $categoryList->toArray();
    }

    /**
     * 生成栏目html
     * @return array
     */
    public function createCategory($categoryId, $param, $hasChild = 1)
    {
        $cateCacheKey = 'hc_cate_html' . $param['admin']['seller_id'] . '_' . $param['site_id'] . '_' . $param['lang'];
//        $list = Cache::get($cateCacheKey);
        if (empty($list)) {
            $listData = $this->updateCategoryCache($param)['data'];
            $listArr = $listData['list'];
        }

        $subIds = [];

        $where = [
            ['seller_id', '=', $param['admin']['seller_id']],
            ['website_id', '=', $param['site_id']],
            ['type', '<>', 3],
        ];
        if (empty($param['lang'])) {
            $param['lang'] = 'zh';
        }
        $where[] = ['lang', '=', $param['lang']];

        if (!empty($categoryId)) {
            if ($hasChild == 1) {
                get_sub_ids($categoryId, $subIds, $listArr);
            }
            $subIds[] = $categoryId; // 包含自己
            $where[] = ['id', 'in', $subIds];
        }

        $Website = new Website();
        $website = $Website->getWebsite(['id' => $param['site_id'], 'seller_id' => $param['admin']['seller_id']])['data'];
        $domain = $website['domain'];

        $list = $this->getCategoryList($where, $param, $domain, $website);


        $this->init($param['admin'], $param['site_id'], $param['lang']);

        $categoryModel = new Category();
        $rootDomain = url_root($domain);

        try {
            foreach ($list as $value) {
                // TODO 生成每个栏目的HTML
                $id = $value['id'];
                $with = ['thumbnail' => function ($q) {
                    $q->field('id,name,url,type');
                }, 'banner' => function ($q) {
                    $q->field('id,name,url,type');
                }
                ];
                $category = $categoryModel->getCategory(['id' => $id, 'seller_id' => $param['admin']['seller_id'], 'website_id' => $param['site_id'], 'lang' => $this->lang], $with)['data']->toArray();
                $this->assign('current_cate', $category);
                $this->assign('root_domain', $rootDomain);
                $template = $category['list_tpl'];
                $html = $this->fetch($template);

                // 静态文件保存路径
                $filePath = CMS_ROOT . 'public' . $value['path'];
                createFile($filePath);
                file_put_contents($filePath, $html);
            }
        } catch (\Exception $e) {
            Log::info($e->getMessage() . $e->getTraceAsString());
            return dataReturn(-3, lang('生成失败'));
        }
        return dataReturn(0, lang('生成成功'));
    }

    /**
     * 生成文章html
     * @return array
     */
    public function createContent($categoryId, $param)
    {
        $listData = $this->updateCategoryCache($param)['data'];
        $listArr = $listData['list'];
        $categoryList = array_column($listArr, null, 'id');

        $where = [];
        if (!empty($categoryId)) {
            $subIds = [];
            get_sub_ids($categoryId, $subIds, $listArr);
            $subIds[] = $categoryId; // 包含自己
            $categoryContentModel = new CategorySubContent();
            $ids = $categoryContentModel->where('category_id', 'in', $subIds)->column('sub_content_id');
            $where[] = ['id', 'in', $ids];
        }

        $contentModel = new SubContent();
        $contentList = $contentModel->where($where)->select()->toArray();

        $Website = new Website();
        $website = $Website->getWebsite(['id' => $param['site_id'], 'seller_id' => $param['admin']['seller_id']])['data'];
        $domain = $website['domain'];

        $this->init($param['admin'], $param['site_id'], $param['lang']);

        try {
            foreach ($contentList as $value) {
                if (empty($categoryList[$value['category_id']])) {
                    continue;
                }
                // 获取生成文件路径
                $detailPath = CMS_ROOT . 'public' . $categoryList[$value['category_id']]['detailPath'] . $value['id'] . '.' . config('route.url_html_suffix');
                $detailPath = str_replace('//', '/', $detailPath);
                // TODO 生成每个页面的HTML
                // 直接curl请求页面拿html
                $url = $domain . $categoryList[$value['category_id']]['detailPath'] . $value['id'] . '.' . config('route.url_html_suffix');

                $html = curlGet($url)['data'];
                createFile($detailPath);
                file_put_contents($detailPath, $html);
            }
        } catch (\Exception $e) {
            Log::info($e->getTraceAsString());
            return dataReturn(-3, lang('生成失败') . $e->getMessage(), $e->getTrace());
        }
        return dataReturn(0, lang('生成成功'));
    }

    public function createHtml()
    {

    }

    /**
     * 定位模板
     * @param $template
     * @return string
     */
    private function parseTemplate($template): string
    {
        $path = CMS_ROOT . $this->viewBase . DIRECTORY_SEPARATOR . $this->realSiteId . DIRECTORY_SEPARATOR . $this->lang . DIRECTORY_SEPARATOR . $this->theme;
        $ext = getFileExt($template);
        $path .= DIRECTORY_SEPARATOR . ltrim($template, '/');
        if ($ext != config('view.view_suffix')) {
            $path .= '.' . config('view.view_suffix');
        }
        return $path;
    }

    /**
     * 常量替换
     * @param $siteId
     * @param $lang
     * @param $themeName
     */
    protected function _initializeView($siteId, $lang, $themeName)
    {
        $viewReplaceStr = [
            '__TMPL__' => "/themes/website/{$siteId}/{$lang}/{$themeName}",
            '__STATIC__' => empty($this->settingData['static_file']) ? "/themes/website/{$siteId}/{$lang}/{$themeName}/static" : $this->settingData['static_file'],
        ];
        View::engine()->config([
            'view_path' => CMS_ROOT . $this->viewBase . DIRECTORY_SEPARATOR . $siteId . DIRECTORY_SEPARATOR . $this->lang . DIRECTORY_SEPARATOR . $this->theme . DIRECTORY_SEPARATOR,
            'tpl_replace_string' => $viewReplaceStr,
            'display_cache' => false,
            'tpl_cache' => false,
        ]);
    }

    /**
     * 加载模板输出
     * @access protected
     * @param string $template 模板文件名
     * @param array $vars 模板输出变量
     * @return mixed
     */
    protected function fetch(string $template = '', array $vars = [])
    {
        $template = $this->parseTemplate($template);
        $this->_initializeView($this->realSiteId, $this->lang, $this->theme);

        $html = View::fetch($template, $vars);
        $replace = <<<EOL
<script id="baseJs" src="/system_file/js/base.min.js"></script>
</head>
EOL;
        $html = str_replace('</head>', $replace, $html);
        return $html;
    }

    protected function assign($name, $value = ''): \think\View
    {
        return View::assign($name, $value);
    }
}
